import { systemService } from "@/modules/model/service";
import { Action, ActionKey } from "@/action/Action";
import { GraphNode } from "../../project/GraphNode";
import { modelService } from "../../service";
import ChooseElement from "@/common/ChooseElement.vue";
import { MenuItem } from "@/constants/types";
import { Shape, GraphModel } from "@/mdesign-lib/mdesign-graph.umd.js";
import { actionManager } from "@/action/ActionManager";
import { OpenCreateElementAction } from "./OpenCreateElementAction";
import { StType } from "@/constants/StType";
import { LicenseService } from "@/modules/license/service/LicenseService";
import { CreateIBDDiagramAction } from "./CreateIBDDiagramAction";
import { CreatePARDiagramAction } from "./CreatePARDiagramAction";
import { MenuItemSpec } from "@/config/customSystemConfig/customSystemConfigTypes";
import { customSystemConfig } from "@/config/customSystemConfig/index";
import { arrayEqual } from "@/util/common";
import { stepMessageHandler } from "../../socket/StepMessageHandler";
import { ganttConfig } from "@/modules/model/comps/station/graphTabs/ganttChartDiagram/config";
import { tableBaseConfigMap } from "@/modules/model/comps/station/graphTabs/diagramTableNew/config/toolBar";

import { AuthorizedFeatures, Features } from "@/util/AuthorizedFeatures";
import { KeyboardEventArea } from "@/constants/Enums";
export class OpenCreateDiagramAction extends Action {
  keyName = ActionKey.openCreateDiagram;
  desc = "";
  bindKey = "Ctrl+Shift+D";
  keyboardArea = KeyboardEventArea.ModelTree;

  async run(ownerId: string | string[], hideWhenEmpty = false) {
    const ownerIds = Array.isArray(ownerId) ? ownerId : [ownerId];
    const isMultiple = ownerIds.length > 1;
    if (!app.isAppActive) {
      LicenseService.tipToActiveLicense();
      return;
    }
    if (!ownerIds.length) throw new Error("没有对应的model id，无法打开创建图！");
    const project = app.activeProject;
    if (!project) return;
    // 协同项目未登录情况，不可新建
    if (project.config.online && !app.global.user) return;
    // 存在未检入的节点，不可新建
    const graphNodes = ownerIds.map(id => project.nodePool.getNode(id));
    if (graphNodes.some(node => node?.disabled)) return;
    // 编辑扩展包时，根节点不允许创建元素
    if (app.activeProject?.config.isProfile && graphNodes.some(node => !node?.data.ownerId)) {
      return;
    }
    try {
      project.attributeTabsModel.ignoreJavaModelChange = true;
      const x = (window.event as MouseEvent)?.clientX || 100;
      const y = (window.event as MouseEvent)?.clientY - 30 || 100;
      if (x === undefined || y === undefined) {
        console.error("x or y is undefined", { x, y });
        return;
      }
      // 获取可创建图的menu
      let list: MenuItem[];
      if (!isMultiple) {
        list = await modelService.getCanCreateDiagramTypes(project.id, ownerIds[0]);
      } else {
        list = await modelService.getMultipleCanCreateDiagramTypes(project.id, ownerIds);
      }
      if (customSystemConfig?.createDiagramMenu?.visibleItems) {
        const visibleItems = customSystemConfig.createDiagramMenu.visibleItems;
        list.forEach(menu => {
          if (!menu.children) return;
          menu.children = menu.children.filter(item => this.filterVisibleItems(visibleItems, item));
        });
      }
      list = list.filter(menu => menu.children?.length);

      if (hideWhenEmpty && list.length === 0) {
        return;
      }
      // if (list.length == 0) return;

      const result: MenuItem = await ChooseElement.popup({
        x,
        y,
        title: "新建图表",
        list: list // [{ label: '常用元素', children: list, value: '' }]
      }).catch((e: any) => {
        e && console.error(e);
      });
      if (!result) return;
      // if (!isMultiple) {
      //   await this.createGraph(result, project.id, ownerIds[0]);
      // } else {
      //   await this.batchCreateGraph(result, project.id, ownerIds);
      // }
      // await Promise.all(ownerIds.map(id => this.createGraph(result, project.id, id)));

      // 队列执行 createCreateGraph 方法快速创建图模型
      for (let i = 0; i < ownerIds.length; i++) {
        const id = ownerIds[i];
        try {
          await this.createGraph(result, project.id, id);
        } catch (e) {
          console.warn(e);
        }
      }
    } finally {
      project.attributeTabsModel.ignoreJavaModelChange = false;
    }
  }

  /**
   * 创建单个图表
   * @param result
   * @param projectId
   * @param ownerId
   * @param isAutoOpenDiagram
   * @param isOnContentDiagram
   * @returns
   */
  async createGraph(result: MenuItem, projectId: string, ownerId: string, isAutoOpenDiagram = true, isOnContentDiagram = false) {
    // createPARDiagram
    await this.setDiagramMaxSize(result.appliedStereotypes);
    const generationConfigs = await modelService.getGenerationConfig({ projectId, modelIds: result.appliedStereotypes as string[] });
    const allSt = new Set<string>();
    generationConfigs.forEach(it => {
      allSt.add(it.id);
      allSt.addAll(it.parentSts);
    });
    if (allSt.has(StType["SysMLDI::ProfileDiagram"])) {
      if (!AuthorizedFeatures.hasAuth(Features.customization)) {
        return;
      }
    }

    if (allSt.has(StType["Customization::DocumentTemplateDiagram"])) {
      if (!AuthorizedFeatures.hasAuth(Features.mDoc)) {
        return;
      }
    }

    if (
      allSt.has(StType["ReliabilityProfile::CustomizationOfFMEA::FaultTreeDiagram"]) ||
      allSt.has(StType["ReliabilityProfile::606Profile::FMECATable"]) ||
      allSt.has("73509885724394816") ||
      allSt.has("73687435145439360") ||
      allSt.has("73509973323144576") ||
      allSt.has("73509919047291968") ||
      allSt.has("73511282487416256")
    ) {
      if (!AuthorizedFeatures.hasAuth(Features.reliability)) {
        return;
      }
    }

    if (allSt.has(StType["SysMLDI::SimulationConfigDiagram"]) || allSt.has(StType["SysMLDI::UserInterfaceModelingDiagram"])) {
      if (!AuthorizedFeatures.hasAuth(Features.simulation)) {
        return;
      }
    }

    if (allSt.has(StType["SysMLDI::SysMLParametricDiagram"])) {
      const action = actionManager.getAction(ActionKey.createPARDiagram) as CreatePARDiagramAction;
      if (!action?.run) return;
      return action.run(result, { projectId, modelId: ownerId, baseSt: (result.appliedStereotypes as string[])[0] }, false);
    }
    if (allSt.has(StType["SysMLDI::SysMLInternalBlockDiagram"])) {
      const action = actionManager.getAction(ActionKey.createIBDDiagram) as CreateIBDDiagramAction;
      if (!action?.run) return;
      return action.run(result, { projectId, modelId: ownerId, baseSt: (result.appliedStereotypes as string[])[0] }, false);
    }

    const sts = result.appliedStereotypes?.[0] || "";

    if (tableBaseConfigMap.get(sts)?.createTableParams?.showWindow) {
      const action = actionManager.getAction("createTableWizard");
      action?.run(projectId, {
        appliedStereotypes: result.appliedStereotypes,
        metaclass: result.metaclass,
        ownerId,
        defaultTableName: result.cnName
      });
      return;
    }

    if (ganttConfig[sts]?.createGanttParams?.showWindow) {
      const action = actionManager.getAction("createGanttWizard");
      action?.run(projectId, {
        appliedStereotypes: result.appliedStereotypes,
        metaclass: result.metaclass,
        ownerId,
        defaultTableName: result.cnName
      });
      return;
    }

    const p = stepMessageHandler.waitModelTreeUpdateOver();
    // const nodeDatas = await modelService.addModel(projectId, ownerId, result.metaclass, result.appliedStereotypes);
    const nodeDatas = await modelService.addModel(
      projectId,
      ownerId,
      result.metaclass,
      result.appliedStereotypes,
      undefined,
      isAutoOpenDiagram
    );
    const targetModel = nodeDatas.find(model => model.metaclass === result.metaclass); // 只判断了metaclass，目前够用
    await p;

    if (app.global.isIpcWindow && !isOnContentDiagram) {
      // 导航图中创建视图不需要浮窗
      // 将新建的图表浮窗到对应的窗口(在该浮窗新建本身就会为当前窗口的graphTabs新增一条数据，所以这里只需将其状态更新即可，但是主窗口也会新增一条，需要将主窗的改数据状态更新成浮动)
      app.activeProject?.ui.onFloatingNewGraph();
    }

    if (!app.global.isIpcWindow) {
      if (targetModel) {
        // 选中模型， 进入编辑状态
        await (actionManager.getAction(ActionKey.openCreateElement) as OpenCreateElementAction).afterCreateModel(targetModel.id);
      } else {
        console.error("缺少返回模型");
      }
    }
    return targetModel?.id;
  }

  /**
   * 批量创建图表
   * @param result
   * @param projectId
   * @param ownerId
   * @param isAutoOpenDiagram
   * @param isOnContentDiagram
   * @returns
   */
  // async batchCreateGraph(result:MenuItem, projectId:string, ownerIds:string[], isAutoOpenDiagram = true, isOnContentDiagram = false) {
  //   // createPARDiagram
  //   await this.setDiagramMaxSize(result.appliedStereotypes);
  //   const generationConfigs = await modelService.getGenerationConfig({ projectId, modelIds: result.appliedStereotypes as string[] });
  //   const allSt = new Set<string>();
  //   generationConfigs.forEach(it => {
  //     allSt.add(it.id);
  //     allSt.addAll(it.parentSts);

  //   });
  //   if (allSt.has(StType['SysMLDI::ProfileDiagram'])) {
  //     if (!AuthorizedFeatures.hasAuth(Features.customization)) {
  //       return;
  //     }
  //   }

  //   if (allSt.has(StType['Customization::DocumentTemplateDiagram'])) {
  //     if (!AuthorizedFeatures.hasAuth(Features.mDoc)) {
  //       return;
  //     }
  //   }

  //   if (allSt.has(StType['ReliabilityProfile::CustomizationOfFMEA::FaultTreeDiagram']) ||
  //   allSt.has(StType["ReliabilityProfile::606Profile::FMECATable"]) ||
  //   allSt.has("73509885724394816") || allSt.has("73687435145439360") || allSt.has("73509973323144576") || allSt.has("73509919047291968") || allSt.has("73511282487416256")

  //   ) {
  //     if (!AuthorizedFeatures.hasAuth(Features.reliability)) {
  //       return;
  //     }
  //   }

  //   if (allSt.has(StType['SysMLDI::SimulationConfigDiagram']) || allSt.has(StType['SysMLDI::UserInterfaceModelingDiagram'])) {
  //     if (!AuthorizedFeatures.hasAuth(Features.simulation)) {
  //       return;
  //     }
  //   }
  //   if (allSt.has(StType['SysMLDI::SysMLParametricDiagram'])) {
  //     const action = actionManager.getAction(ActionKey.createPARDiagram) as CreatePARDiagramAction;
  //     if (!action?.run) return;
  //     action.run(result, { projectId, modelIds: ownerIds, baseSt: (result.appliedStereotypes as string[])[0] }, false);
  //     return;
  //   } else if (allSt.has(StType['SysMLDI::SysMLInternalBlockDiagram'])) {
  //     const action = actionManager.getAction(ActionKey.createIBDDiagram) as CreateIBDDiagramAction;
  //     if (!action?.run) return;
  //     action.run(result, { projectId, modelIds: ownerIds, baseSt: (result.appliedStereotypes as string[])[0] }, false);
  //     return;
  //   }
  //   const p = stepMessageHandler.waitModelTreeUpdateOver();

  //   const nodeDatas = await modelService.addModel(projectId, ownerId, result.metaclass, result.appliedStereotypes, undefined, isAutoOpenDiagram);
  //   const targetModel = nodeDatas.find(model => model.metaclass === result.metaclass); // 只判断了metaclass，目前够用
  //   await p;

  //   if (app.global.isIpcWindow && !isOnContentDiagram) { // 导航图中创建视图不需要浮窗
  //     // 将新建的图表浮窗到对应的窗口(在该浮窗新建本身就会为当前窗口的graphTabs新增一条数据，所以这里只需将其状态更新即可，但是主窗口也会新增一条，需要将主窗的改数据状态更新成浮动)
  //     app.activeProject?.ui.onFloatingNewGraph();
  //   }

  //   if (!app.global.isIpcWindow) {
  //     if (targetModel) {

  //       // 选中模型， 进入编辑状态
  //       await (actionManager.getAction(ActionKey.openCreateElement) as OpenCreateElementAction).afterCreateModel(targetModel.id);

  //     } else {
  //       console.error('缺少返回模型');
  //     }
  //   }
  //   return targetModel?.id;
  // }

  async onTreeMenuClick(graphNode: GraphNode) {
    if (!graphNode) throw new Error("graphNode不存在！");
    if (graphNode.disabled) return;

    // 需要判断选中单个模型还是多个模型
    const project = app.activeProject!;
    const selectedIds = project.nodePool.selectedNodeIds;
    if (selectedIds.length > 1) {
      this.run(selectedIds);
    } else {
      this.run(graphNode.id);
    }
  }

  onShapeMenuClick(graph: GraphModel, shape: Shape) {
    if (!shape) throw new Error("shape不存在！");
    this.run(shape.modelId);

    // 需要判断选中单个图元还是多个图元
    const shapes = graph.selectionModel.selection;
    if (shapes.length > 1) {
      this.run(shapes.map(it => it.modelId));
    } else {
      this.run(shape.modelId);
    }
  }

  onKeyboardEvent() {
    const project = app.activeProject;
    if (!project) throw new Error("没有打开项目");
    const nodes = project.nodePool.getSelectedNodes();
    if (nodes.length == 1) {
      this.run(nodes[0].id, true);
    }
  }

  // 获取图表初始宽高
  async setDiagramMaxSize(sts: string[] = []) {
    const isRelationDiagram =
      sts.includes(StType["TableAndMatrix::CustomizeMap::DiagramMap"]) ||
      sts.includes(StType["TableAndMatrix::CustomizeMap::RequirementRelationMap"]) ||
      sts.includes(StType["TableAndMatrix::CustomizeMap::StructureDecompositionMap"]) ||
      sts.includes(StType["TableAndMatrix::CustomizeMap::ActivityDecompositionMap"]) ||
      sts.includes(StType["TableAndMatrix::CustomizeMap::ChangeAnalysisMap"]);

    const isModelicaIBD = sts.includes("71860099812732608");
    const bodyHeight = document.body.clientHeight;
    const bodyWidth = document.body.clientWidth;
    const sideBarWidth = document.querySelector(".v-station ._station-sider")?.clientWidth || 0;
    const windowHeight = document.querySelector(".v-window-bar")?.clientHeight || 0;
    const headerHeight = document.querySelector(".v-header")?.clientHeight || 0;
    const footBarHeight = document.querySelector(".v-station-footer")?.clientHeight || 0;
    const relationDiagramToolBarHeight = isRelationDiagram ? 40 : 0;
    const diagramTop = 28 * 2;
    const diagramLeft = isRelationDiagram ? 0 : 163;
    const marginLeft = 12;
    const marginRight = 30;
    const diagramMaxWidth = bodyWidth - sideBarWidth - diagramLeft - marginLeft - marginRight;
    const diagramMaxHeight =
      bodyHeight - windowHeight - headerHeight - relationDiagramToolBarHeight - diagramTop - marginLeft - marginRight - footBarHeight;
    const minSize = 200;
    // console.log('diagramMaxWidth', diagramMaxWidth, diagramMaxHeight);
    let mWidth = Math.max(diagramMaxWidth, minSize);
    let mHeight = Math.max(diagramMaxHeight, minSize);
    if (isModelicaIBD) {
      const max = Math.max(mHeight, mWidth);
      mWidth = max;
      mHeight = max;
    }
    await systemService.updateDiagramSize({ width: mWidth, height: mHeight });
  }

  filterVisibleItems(visibleItems: MenuItemSpec[], item: MenuItem): boolean {
    return !!visibleItems.find(it => {
      if (it.metaclass !== item.metaclass) return false;
      if (item.appliedStereotypes) {
        if (!it.appliedStereotypes) {
          return false;
        }
        if (!arrayEqual(it.appliedStereotypes, item.appliedStereotypes)) {
          return false;
        }
      }
      return true;
    });
  }
}
